home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Environments / Frontier 4.0.1 / Frontier SDK 4.0b2 / Sample Code / Frontier Do-Script / Apple Event Do-Script / main.c < prev   
Encoding:
C/C++ Source or Header  |  1996-01-26  |  11.5 KB  |  587 lines  |  [TEXT/CWIE]

  1.  
  2. /*© copyright 1991-96 UserLand Software, Inc. All Rights Reserved.*/
  3.  
  4.  
  5. /*
  6. Frontier Do-Script -- Drives Frontier's "do-script" Apple event. You can send 
  7. any valid Frontier script across this channel. 
  8.  
  9. This program starts by sending a script with a syntax error, to test the error
  10. reporting mechanism.
  11.  
  12. This is a very bare bones program with one window and no menu bar. To quit FDS
  13. just close the window.
  14.  
  15. IMPORTANT NOTE: This version of Frontier Do-Script is primarily intended for
  16. developers who are building directly on top of the Apple Event Manager. If you're
  17. using the IAC Tools library implemented in iac.c, crib the version of FDS from
  18. the Applet Toolkit doscript.c file. It calls IAC Tools routines to talk to 
  19. Frontier.
  20.  
  21. New in Frontier 3.0 -- see the Component Do-Script folder. If you know that
  22. you're talking to Frontier 3.0, and can assume that your users have System 7.1
  23. or QuickTime, the component version of FDS is much faster than this version.
  24. */
  25.  
  26.  
  27. #include <AppleEvents.h>
  28.  
  29. WindowPtr mainwindow = nil; /*the menu sharing test window*/
  30.  
  31. Str255 windowmessage; /*the message that's displayed in the main window*/
  32.     
  33.     
  34.  
  35.  
  36. static void initmacintosh (void) {
  37.  
  38.     /*
  39.     the magic stuff that every Macintosh application needs to do 
  40.     before doing anything else.
  41.     */
  42.  
  43.     short i;
  44.         
  45.     MaxApplZone ();
  46.     
  47.     InitGraf (&qd.thePort);
  48.     
  49.     InitFonts ();
  50.     
  51.     FlushEvents (everyEvent, 0);
  52.     
  53.     InitWindows ();
  54.     
  55.     InitMenus ();
  56.     
  57.     TEInit ();
  58.     
  59.     InitDialogs (nil);
  60.     
  61.     InitCursor ();
  62.     
  63.     for (i = 0; i < 5; i++) { /*register with Multifinder*/
  64.         
  65.         EventRecord ev;
  66.         
  67.         EventAvail (everyEvent, &ev); /*see TN180 -- splash screen*/
  68.         } /*for*/
  69.         
  70.     DrawMenuBar ();
  71.     } /*initmacintosh*/
  72.  
  73.  
  74. static void copystring (Str255 source, Str255 dest) {
  75.  
  76.     /*
  77.     create a copy of source in dest.  copy the length byte and
  78.     all the characters in the source string.
  79.  
  80.     assume the strings are pascal strings, with the length byte in
  81.     the first character of the string.
  82.     */
  83.  
  84.     short i, len;
  85.     
  86.     len = (short) source [0];
  87.     
  88.     for (i = 0; i <= len; i++) 
  89.         dest [i] = source [i];
  90.     } /*copystring*/
  91.  
  92.  
  93. static Boolean pushstring (Str255 bssource, Str255 bsdest) {
  94.  
  95.     short lensource = bssource [0];
  96.     short lendest = bsdest [0];
  97.     char *psource, *pdest;
  98.     
  99.     if ((lensource + lendest) > 255)
  100.         return (false);
  101.         
  102.     pdest = (char *) bsdest + (char) lendest + 1;
  103.     
  104.     psource = (char *) bssource + 1;
  105.     
  106.     bsdest [0] += (char) lensource;
  107.     
  108.     while (lensource--) *pdest++ = *psource++;
  109.     
  110.     return (true);
  111.     } /*pushstring*/
  112.     
  113.     
  114. static Boolean pushlong (long num, Str255 bsdest) {
  115.  
  116.     Str255 bsint;
  117.     
  118.     NumToString (num, bsint);
  119.     
  120.     return (pushstring (bsint, bsdest));
  121.     } /*pushlong*/
  122.     
  123.  
  124. static void ellipsize (Str255 s, short width) {
  125.  
  126.     /*
  127.     if the string fits inside the given number of pixels, fine -- do nothing
  128.     and return.
  129.     
  130.     if not, return a string that does fit, with ellipses representing the 
  131.     deleted characters.  ellipses are generated by pressing option-semicolon.
  132.     */
  133.     
  134.     char len;
  135.     short newwidth;
  136.     
  137.     if ((newwidth = StringWidth (s)) <= width) /*nothing to do, the string fits*/
  138.         return;
  139.     
  140.     len = s [0]; /* current length in characters*/
  141.     
  142.     width -= CharWidth ('…'); /* subtract width of ellipses*/
  143.         
  144.     do { /*until it fits (or we run out of characters)*/
  145.     
  146.         newwidth -= CharWidth (s [len]);
  147.         
  148.         --len;
  149.     } while ((newwidth > width) && (len != 0));
  150.     
  151.     ++len; /*make room for the ellipses*/
  152.     
  153.     s [len] = '…'; 
  154.     
  155.     s [0] = (char) len;
  156.     } /*ellipsize*/
  157.  
  158.  
  159. static void centerstring (Rect r, Str255 s) {
  160.     
  161.     /*
  162.     draw the string in the current font, size and style, centered inside
  163.     the indicated rectangle.
  164.     */
  165.     
  166.     short rh = r.bottom - r.top;
  167.     short rw = r.right - r.left;
  168.     short h, v;
  169.     FontInfo fi;
  170.     
  171.     GetFontInfo (&fi);
  172.     
  173.     ellipsize (s, rw); /*make sure it fits inside the rectangle, width-wise*/
  174.     
  175.     h = r.left + ((rw - StringWidth (s)) / 2);
  176.     
  177.     v = r.top + ((rh - (fi.ascent + fi.descent)) / 2) + fi.ascent;
  178.     
  179.     MoveTo (h, v);
  180.     
  181.     ClipRect (&r);
  182.     
  183.     DrawString (s);
  184.     } /*centerstring*/
  185.  
  186.  
  187. static void setfontsizestyle (short fontnum, short fontsize, short fontstyle) {
  188.  
  189.     TextFont (fontnum);
  190.     
  191.     TextSize (fontsize);
  192.     
  193.     TextFace (fontstyle);
  194.     } /*setfontsizestyle*/
  195.     
  196.     
  197. static void updatemainwindow (void) {
  198.     
  199.     Rect r;
  200.     Str255 s;
  201.     
  202.     r = (*mainwindow).portRect;
  203.     
  204.     EraseRect (&r);
  205.     
  206.     setfontsizestyle (helvetica, 12, 0);
  207.     
  208.     centerstring (r, windowmessage);
  209.     
  210.     NumToString (FreeMem () / 1024, s);
  211.     
  212.     MoveTo (r.left + 3, r.bottom - 3);
  213.     
  214.     setfontsizestyle (geneva, 9, 0);
  215.     
  216.     DrawString (s);
  217.     
  218.     DrawString ("\pK");
  219.     } /*updatemainwindow*/
  220.     
  221.     
  222. static void setwindowmessage (Str255 script, Str255 result) {
  223.     
  224.     copystring (script, windowmessage);
  225.             
  226.     pushstring ("\p returns ", windowmessage);
  227.             
  228.     pushstring (result, windowmessage);
  229.     
  230.     pushstring ("\p", windowmessage);
  231.             
  232.     SetPort (mainwindow);
  233.     
  234.     updatemainwindow ();
  235.     } /*setwindowmessage*/
  236.  
  237.  
  238. static Boolean initmainwindow (void) {
  239.     
  240.     WindowPtr w;
  241.     
  242.     w = mainwindow = GetNewWindow (128, nil, (WindowPtr) -1);
  243.     
  244.     if (w == nil)
  245.         return (false);
  246.     
  247.     ShowWindow (w);
  248.     
  249.     return (true);
  250.     } /*initmainwindow*/
  251.  
  252.  
  253. static Boolean stringtotext (Str255 s, Handle *htext) {
  254.     
  255.     long len;
  256.     Handle h;
  257.     
  258.     len = s [0];
  259.     
  260.     h = NewHandle (len);
  261.     
  262.     if (h == nil)
  263.         return (false);
  264.         
  265.     BlockMove (&s [1], *h, len);
  266.     
  267.     *htext = h;
  268.     
  269.     return (true);
  270.     } /*stringtotext*/
  271.     
  272.     
  273. static Boolean texttostring (Handle htext, Str255 s) {
  274.     
  275.     long len;
  276.     
  277.     len = GetHandleSize (htext);
  278.     
  279.     if (len > 255)
  280.         len = 255;
  281.         
  282.     BlockMove (*htext, &s [1], len);
  283.     
  284.     s [0] = (char) len;
  285.     
  286.     return (true);
  287.     } /*texttostring*/
  288.     
  289.     
  290. static Boolean IACpushtextparam (AppleEvent *event, Handle val, OSType keyword) {
  291.  
  292.     AEDesc desc;
  293.     OSErr ec;
  294.     
  295.     desc.descriptorType = 'TEXT';
  296.     
  297.     desc.dataHandle = val;
  298.     
  299.     ec = AEPutParamDesc (event, (AEKeyword) keyword, &desc);
  300.     
  301.     return (ec == noErr);
  302.     } /*IACpushtextparam*/
  303.  
  304.  
  305. static Boolean IACgettextparam (AppleEvent *event, OSType keyword, Handle *htext) {
  306.     
  307.     AEDesc result;
  308.     OSErr ec;
  309.     Boolean fl;
  310.     
  311.     ec = AEGetParamDesc (event, (AEKeyword) keyword, 'TEXT', &result);
  312.     
  313.     if (ec != noErr)
  314.         return (false);
  315.         
  316.     *htext = result.dataHandle;
  317.     
  318.     fl = HandToHand (htext) == noErr;
  319.     
  320.     AEDisposeDesc (&result);
  321.     
  322.     return (fl);
  323.     } /*IACgettextparam*/
  324.  
  325.  
  326. static Boolean IACerrorreply (AppleEvent *reply, Str255 errorstring) {
  327.     
  328.     /*
  329.     return true if the reply is an error -- if so it has an 'errn' value
  330.     and an 'errs' value. if we return false, the reply is not an error.
  331.     */
  332.     
  333.     OSErr ec;
  334.     AEDesc desc;
  335.     
  336.     ec = AEGetParamDesc (reply, (AEKeyword) 'errn', 'shor', &desc);
  337.     
  338.     if (ec != noErr) /*the reply isn't an error*/
  339.         return (false);
  340.  
  341.     AEDisposeDesc (&desc);
  342.     
  343.     ec = AEGetParamDesc (reply, (AEKeyword) 'errs', 'TEXT', &desc);
  344.     
  345.     if (ec != noErr) {
  346.         
  347.         copystring ("\pUnknown error.", errorstring);
  348.         
  349.         return (true);
  350.         }
  351.     else
  352.         texttostring (desc.dataHandle, errorstring);
  353.     
  354.     AEDisposeDesc (&desc);
  355.     
  356.     return (true); /*there was an error returned*/
  357.     } /*IACerrorreply*/
  358.     
  359.  
  360. static pascal short WaitRoutine (ev, sleep, mousergn) EventRecord *ev; long *sleep; RgnHandle *mousergn; {
  361.     
  362.     return (0); /*keep waiting*/
  363.     } /*WaitRoutine*/
  364.  
  365.  
  366. #if GENERATINGCFM
  367.     
  368.     static RoutineDescriptor WaitRoutineDesc = BUILD_ROUTINE_DESCRIPTOR (uppAEIdleProcInfo, WaitRoutine);
  369.     
  370.     #define WaitRoutineUPP (&WaitRoutineDesc)
  371.     
  372. #else
  373.     
  374.     #define WaitRoutineUPP ((AEIdleUPP) WaitRoutine)
  375.  
  376. #endif
  377.  
  378. static Boolean FrontierDoScript (Str255 script, Str255 returns) {
  379.     
  380.     /*
  381.     Send a Do Script message to Frontier. The first parameter contains a short
  382.     script to be run. The second parameter is the string that Frontier returned 
  383.     as the value generated by running the script. 
  384.     
  385.     Returns true if we were able to send the message to Frontier, and Frontier
  386.     was able to compile and run the script and Frontier replied with a returned
  387.     value. FrontierDoScript returns false if Frontier isn't running, or if the
  388.     script didn't compile or if there was a communications error.
  389.     
  390.     Frontier is not limited to running 255-character scripts or returning 
  391.     255-character returned values. This routine can easily be enhanced to handle 
  392.     larger scripts and returned values. 
  393.     
  394.     11/6/91 DW: Set return string to "IAC Error" if we failed to create an Apple
  395.     event descriptor or if the send failed. We're not suggesting that your
  396.     error messages should be so brief, rather they should be custom-fit to the
  397.     appropriate audience. Here, we want to show you how to locate errors relating
  398.     to the IAC channel -- either you're low on memory, or the Apple Event Manager
  399.     isn't present, or Frontier isn't running. Watch for this string in FDS's 
  400.     little window...
  401.     */
  402.  
  403.     OSErr ec;
  404.     AEAddressDesc adr; 
  405.     AppleEvent event, reply;
  406.     OSType idfrontier;
  407.     Handle htext = nil;
  408.     Boolean flhavereply = false;
  409.     
  410.     copystring ("\pIAC Error.", returns); /*default return string*/
  411.     
  412.     idfrontier = 'LAND';
  413.     
  414.     ec = AECreateDesc (typeApplSignature, (Ptr) &idfrontier, sizeof (idfrontier), &adr);
  415.     
  416.     if (ec != noErr)
  417.         return (false);
  418.     
  419.     ec = AECreateAppleEvent (
  420.         
  421.         'misc', 'dosc', &adr, kAutoGenerateReturnID, 
  422.         
  423.         kAnyTransactionID, &event);
  424.     
  425.     AEDisposeDesc (&adr);
  426.     
  427.     if (ec != noErr)
  428.         return (false);
  429.         
  430.     if (!stringtotext (script, &htext))
  431.         return (false);
  432.         
  433.     if (!IACpushtextparam (&event, htext, '----')) {
  434.         
  435.         DisposeHandle (htext);
  436.         
  437.         return (false);
  438.         }
  439.     
  440.     DisposeHandle (htext);
  441.     
  442.     ec = AESend (
  443.         
  444.         &event, &reply, kAEWaitReply + kAECanInteract + kAECanSwitchLayer, 
  445.         
  446.         kAEHighPriority, kNoTimeOut, WaitRoutineUPP, (AEFilterUPP) nil);
  447.     
  448.     if (ec != noErr)
  449.         goto error;
  450.         
  451.     flhavereply = true;
  452.     
  453.     if (IACerrorreply (&reply, returns)) /*syntax error or runtime error*/
  454.         goto error;
  455.         
  456.     if (IACgettextparam (&reply, '----', &htext)) {
  457.     
  458.         texttostring (htext, returns);
  459.     
  460.         DisposeHandle (htext);
  461.         }
  462.     
  463.     AEDisposeDesc (&event);    
  464.     
  465.     AEDisposeDesc (&reply);
  466.     
  467.     return (true);
  468.     
  469.     error:
  470.     
  471.     AEDisposeDesc (&event);    
  472.     
  473.     if (flhavereply)
  474.         AEDisposeDesc (&reply);
  475.     
  476.     return (false);
  477.     } /*FrontierDoScript*/
  478.     
  479.     
  480. static void handledrag (EventRecord ev, WindowPtr w) {
  481.     
  482.     Rect r;
  483.  
  484.     r = qd.screenBits.bounds; 
  485.    
  486.     r.top = r.top + GetMBarHeight (); 
  487.                
  488.     r.left = r.left + 4;  
  489.                
  490.     r.right = r.right - 4;
  491.                
  492.     r.bottom = r.bottom - 4;
  493.              
  494.     DragWindow (w, ev.where, &r);   
  495.     } /*handledrag*/
  496.     
  497.     
  498. static Boolean exitprogram (void) {
  499.     
  500.     /*
  501.     returns true if the user clicks in the go-away box.
  502.     */
  503.     
  504.     EventRecord ev;
  505.     WindowPtr w;
  506.     
  507.     if (!WaitNextEvent (everyEvent, &ev, 1, nil))
  508.         return (false);
  509.     
  510.     if (ev.what != mouseDown)
  511.         return (false);
  512.         
  513.     switch (FindWindow (ev.where, &w)) {
  514.     
  515.         case inGoAway: /*click in go-away box to exit program*/
  516.             return (TrackGoAway (w, ev.where));
  517.         
  518.         case inSysWindow:
  519.             SystemClick (&ev, w); 
  520.             
  521.             return (false);
  522.         
  523.         case inDrag:
  524.             handledrag (ev, w);
  525.             
  526.             return (false);
  527.             
  528.         } /*switch*/
  529.         
  530.     return (false); /*don't exit the program*/
  531.     } /*exitprogram*/
  532.  
  533.  
  534. static void waitseconds (long n) {
  535.     
  536.     long endticks;
  537.     
  538.     endticks = TickCount () + (n * 60);
  539.     
  540.     while (TickCount () < endticks)
  541.         SystemTask ();
  542.     } /*waitseconds*/
  543.  
  544.  
  545. void main (void) {
  546.     
  547.     Str255 script, result;
  548.     Boolean error;
  549.     short i;
  550.     
  551.     initmacintosh ();
  552.     
  553.     initmainwindow (); 
  554.     
  555.     copystring ("\p94 + ", script);
  556.     
  557.     if (FrontierDoScript (script, result))
  558.         copystring ("\pFrontierDoScript should have returned false.", result);
  559.     
  560.     setwindowmessage (script, result); /*should say "Can't compile this script..."*/
  561.     
  562.     waitseconds (1); /*give user a chance to see error message*/
  563.     
  564.     for (i = 1; i <= 50; ++i) {
  565.         
  566.         if (exitprogram ()) /*returns true if user clicks in go away box*/
  567.             return;
  568.         
  569.         copystring ("\pstates.nthState (", script);
  570.         
  571.         pushlong (i, script);
  572.         
  573.         pushstring ("\p)", script);
  574.         
  575.         error = !FrontierDoScript (script, result);
  576.         
  577.         setwindowmessage (script, result);
  578.         
  579.         if (error)
  580.             break;
  581.         } /*while*/
  582.     
  583.     waitseconds (2); /*give user a chance to see the final result*/
  584.     } /*main*/
  585.  
  586.  
  587.